
package com.ibeeking.found.report.rest.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ibeeking.found.report.rest.service.IDataSetParamService;
import com.ibeeking.found.report.rest.service.IDataSetService;
import com.ibeeking.found.report.rest.service.IDataSetTransformService;
import com.ibeeking.found.report.rest.service.IDataSourceService;
import com.ibeeking.found.report.service.common.constant.Enabled;
import com.ibeeking.found.report.service.common.constant.JdbcConstants;
import com.ibeeking.found.report.service.common.constant.enums.SetTypeEnum;
import com.ibeeking.found.report.service.common.dos.DataSetDO;
import com.ibeeking.found.report.service.common.dos.DataSetParamDO;
import com.ibeeking.found.report.service.common.dos.DataSetTransformDO;
import com.ibeeking.found.report.service.common.dos.DataSourceDO;
import com.ibeeking.found.report.service.common.vo.*;
import com.ibeeking.found.report.service.mapper.DataSetMapper;
import com.ibeeking.found.report.service.mapper.ReportBaseMapper;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Raod
 * @desc DataSetDO 数据集服务实现
 * @date 2021-03-18 12:11:31.150755900
 **/
@Service
//@RequiredArgsConstructor
@Slf4j
public class DataSetServiceImpl implements IDataSetService {

    @Resource
    private DataSetMapper dataSetMapper;

    @Resource
    private IDataSetParamService dataSetParamService;

    @Resource
    private IDataSetTransformService dataSetTransformService;

    @Resource
    private IDataSourceService dataSourceService;

    @Override
    public ReportBaseMapper<DataSetDO> getMapper() {
        return dataSetMapper;
    }

    /**
     * 单条详情
     *
     * @param id
     * @return
     */
    @Override
    public DataSetVO detailSet(Long id) {

        DataSetDO result = selectOne(id);
        String setCode = result.getSetCode();
        DataSetVO dto = BeanUtil.convertBean(result, DataSetVO.class);
//        ReportBeanUtils.copyAndFormatter(result, dto);
        return getDetailSet(dto, setCode);
    }

    /**
     * 单条详情
     *
     * @param setCode
     * @return
     */
    @Override
    public DataSetVO detailSet(String setCode) {

        DataSetDO result = selectOne("set_code", setCode);
        DataSetVO dto = BeanUtil.convertBean(result, DataSetVO.class);
//        ReportBeanUtils.copyAndFormatter(result, dto);
        return getDetailSet(dto, setCode);
    }

    public DataSetVO getDetailSet(DataSetVO dto, String setCode) {
        //查询参数
        List<DataSetParamDO> dataSetParamDOList = dataSetParamService.list(
                new QueryWrapper<DataSetParamDO>()
                        .lambda()
                        .eq(DataSetParamDO::getSetCode, setCode)
        );
        List<DataSetParamVO> dataSetParamDtoList = new ArrayList<>();
        dataSetParamDOList.forEach(dataSetParam -> {
            DataSetParamVO dataSetParamDto = BeanUtil.convertBean(dataSetParam, DataSetParamVO.class);
//            ReportBeanUtils.copyAndFormatter(dataSetParam, dataSetParamDto);
            dataSetParamDtoList.add(dataSetParamDto);
        });
        dto.setDataSetParamDtoList(dataSetParamDtoList);

        //数据转换

        List<DataSetTransformDO> dataSetTransformDOList = dataSetTransformService.list(
                new QueryWrapper<DataSetTransformDO>()
                        .lambda()
                        .eq(DataSetTransformDO::getSetCode, setCode)
                        .orderByAsc(DataSetTransformDO::getOrderNum)
        );
        List<DataSetTransformVO> dataSetTransformDtoList = new ArrayList<>();
        dataSetTransformDOList.forEach(dataSetTransform -> {
            DataSetTransformVO dataSetTransformDto = BeanUtil.convertBean(dataSetTransform, DataSetTransformVO.class);
//            ReportBeanUtils.copyAndFormatter(dataSetTransform, dataSetTransformDto);
            dataSetTransformDtoList.add(dataSetTransformDto);
        });
        dto.setDataSetTransformDtoList(dataSetTransformDtoList);

        if (StringUtils.isNotBlank(dto.getCaseResult())) {
            try {
                JSONArray jsonArray = JSONArray.parseArray(dto.getCaseResult());
                JSONObject jsonObject = jsonArray.getJSONObject(0);
                dto.setSetParamList(jsonObject.keySet());
            } catch (Exception e) {
                log.error("error", e);
            }
        }
        return dto;
    }


    /**
     * 新增数据集、添加查询参数、数据转换
     *
     * @param dto
     */
    @Override
    @Transactional
    public DataSetVO insertSet(DataSetVO dto) {
        List<DataSetParamVO> dataSetParamDtoList = dto.getDataSetParamDtoList();
        List<DataSetTransformVO> dataSetTransformDtoList = dto.getDataSetTransformDtoList();

        //1.新增数据集
        DataSetDO dataSetDO = new DataSetDO();
        BeanUtils.copyProperties(dto, dataSetDO);
        if (StringUtils.isNotBlank(dataSetDO.getCaseResult())) {
            try {
                JSONArray objects = JSONObject.parseArray(dataSetDO.getCaseResult());
                if (objects.size() > 1) {
                    Object o = objects.get(0);
                    objects = new JSONArray();
                    objects.add(o);
                    dataSetDO.setCaseResult(JSON.toJSONString(objects, SerializerFeature.WriteMapNullValue));
                }
            } catch (Exception e) {
                log.info("结果集只保留一行数据失败...{}", e.getMessage());
            }
        }
        insert(dataSetDO);
        //2.更新查询参数
        dataSetParamBatch(dataSetParamDtoList, dto.getSetCode());

        //3.更新数据转换
        dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode());
        return dto;
    }

    /**
     * 更新数据集、添加查询参数、数据转换
     *
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSet(DataSetVO dto) {
        List<DataSetParamVO> dataSetParamDtoList = dto.getDataSetParamDtoList();
        List<DataSetTransformVO> dataSetTransformDtoList = dto.getDataSetTransformDtoList();
        //1.更新数据集
        DataSetDO dataSetDO = new DataSetDO();
        BeanUtils.copyProperties(dto, dataSetDO);
        if (StringUtils.isNotBlank(dataSetDO.getCaseResult())) {
            try {
                JSONArray objects = JSONObject.parseArray(dataSetDO.getCaseResult());
                if (objects.size() > 1) {
                    Object o = objects.get(0);
                    objects = new JSONArray();
                    objects.add(o);
                    dataSetDO.setCaseResult(JSON.toJSONString(objects, SerializerFeature.WriteMapNullValue));
                }
            } catch (Exception e) {
                log.info("结果集只保留一行数据失败...{}", e.getMessage());
            }
        }
        update(dataSetDO);

        //2.更新查询参数
        dataSetParamBatch(dataSetParamDtoList, dto.getSetCode());

        //3.更新数据转换
        dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode());
    }


    /**
     * 删除数据集、添加查询参数、数据转换
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSet(Long id) {
        DataSetDO dataSetDO = selectOne(id);
        String setCode = dataSetDO.getSetCode();
        //1.删除数据集
        deleteById(id);

        //2.删除查询参数
        dataSetParamService.delete(
                new QueryWrapper<DataSetParamDO>()
                        .lambda()
                        .eq(DataSetParamDO::getSetCode, setCode)
        );

        //3.删除数据转换
        dataSetTransformService.delete(
                new QueryWrapper<DataSetTransformDO>()
                        .lambda()
                        .eq(DataSetTransformDO::getSetCode, setCode)
        );
    }

    /**
     * 获取数据
     *
     * @param dto
     * @return
     */
    @Override
    public OriginalDataVO getData(DataSetVO dto) {

        OriginalDataVO originalDataVO = new OriginalDataVO();
        String setCode = dto.getSetCode();
        if (StringUtils.isBlank(setCode)) {
            return new OriginalDataVO(new ArrayList<>());
        }
        //1.获取数据集、参数替换、数据转换
        DataSetVO dataSetVO = detailSet(setCode);
        String dynSentence = dataSetVO.getDynSentence();
        //2.获取数据源
        DataSourceDO dataSourceDO;
        if (StringUtils.isNotBlank(dataSetVO.getSetType())
                && dataSetVO.getSetType().equals(SetTypeEnum.HTTP.getCodeValue())) {
            //http不需要数据源，兼容已有的逻辑，将http所需要的数据塞进DataSource
            dataSourceDO = new DataSourceDO();
            dataSourceDO.setSourceConfig(dynSentence);
            dataSourceDO.setSourceType(JdbcConstants.HTTP);
            String body = JSONObject.parseObject(dynSentence).getString("body");
            if (StringUtils.isNotBlank(body)) {
                dynSentence = body;
            } else {
                dynSentence = "{}";
            }

        } else {
            dataSourceDO = dataSourceService.selectOne("source_code", dataSetVO.getSourceCode());
        }

        //3.参数替换
        //3.1参数校验
        log.debug("参数校验替换前：{}", dto.getContextData());
        boolean verification = dataSetParamService.verification(dataSetVO.getDataSetParamDtoList(), dto.getContextData());
        if (!verification) {
            throw new BusinessException("Rule fields check error");
        }
        dynSentence = dataSetParamService.transform(dto.getContextData(), dynSentence);
        log.debug("参数校验替换后：{}", dto.getContextData());
        //4.获取数据
        DataSourceVO dataSourceVO = new DataSourceVO();
        BeanUtils.copyProperties(dataSourceDO, dataSourceVO);
        dataSourceVO.setDynSentence(dynSentence);
        dataSourceVO.setContextData(dto.getContextData());
        //获取total,判断contextData中是否传入分页参数
        if (null != dto.getContextData()
                && dto.getContextData().containsKey("pageNumber")
                && dto.getContextData().containsKey("pageSize")) {
            long total = dataSourceService.total(dataSourceVO, dto);
            originalDataVO.setTotal(total);
        }
        List<JSONObject> data = dataSourceService.execute(dataSourceVO);
        //5.数据转换
        List<JSONObject> transform = dataSetTransformService.transform(dataSetVO.getDataSetTransformDtoList(), data);
        originalDataVO.setData(transform);
        return originalDataVO;
    }

    /**
     * @param dto
     * @return
     */
    @Override
    public OriginalDataVO testTransform(DataSetVO dto) {
        String dynSentence = dto.getDynSentence();

        OriginalDataVO originalDataVO = new OriginalDataVO();
        String sourceCode = dto.getSourceCode();
        //1.获取数据源
        DataSourceDO dataSourceDO;
        if (dto.getSetType().equals(SetTypeEnum.HTTP.getCodeValue())) {
            //http不需要数据源，兼容已有的逻辑，将http所需要的数据塞进DataSource
            dataSourceDO = new DataSourceDO();
            dataSourceDO.setSourceConfig(dynSentence);
            dataSourceDO.setSourceType(JdbcConstants.HTTP);
            String body = JSONObject.parseObject(dynSentence).getString("body");
            if (StringUtils.isNotBlank(body)) {
                dynSentence = body;
            } else {
                dynSentence = "{}";
            }

        } else {
            dataSourceDO = dataSourceService.selectOne("source_code", sourceCode);
        }

        //3.参数替换
        //3.1参数校验
        boolean verification = dataSetParamService.verification(dto.getDataSetParamDtoList(), null);
        if (!verification) {
            throw new BusinessException("Rule fields check error");
        }

        dynSentence = dataSetParamService.transform(dto.getDataSetParamDtoList(), dynSentence);
        //4.获取数据
        DataSourceVO dataSourceVO = new DataSourceVO();
        BeanUtils.copyProperties(dataSourceDO, dataSourceVO);
        dataSourceVO.setDynSentence(dynSentence);
        dataSourceVO.setContextData(setContextData(dto.getDataSetParamDtoList()));

        //获取total,判断DataSetParamDtoList中是否传入分页参数
        Map<String, Object> collect = dto.getDataSetParamDtoList().stream().collect(Collectors.toMap(DataSetParamVO::getParamName, DataSetParamVO::getSampleItem));
        if (collect.containsKey("pageNumber") && collect.containsKey("pageSize")) {
            dto.setContextData(collect);
            long total = dataSourceService.total(dataSourceVO, dto);
            originalDataVO.setTotal(total);
        }

        List<JSONObject> data = dataSourceService.execute(dataSourceVO);
        //5.数据转换
        List<JSONObject> transform = dataSetTransformService.transform(dto.getDataSetTransformDtoList(), data);
        originalDataVO.setData(transform);
        return originalDataVO;
    }


    /**
     * 获取所有数据集
     *
     * @return
     */
    @Override
    public List<DataSetDO> queryAllDataSet() {
        LambdaQueryWrapper<DataSetDO> wrapper = Wrappers.lambdaQuery();
        wrapper.select(DataSetDO::getSetCode, DataSetDO::getSetName, DataSetDO::getSetDesc, DataSetDO::getId)
                .eq(DataSetDO::getPublishStatus, Enabled.YES.getValue());
        wrapper.orderByDesc(DataSetDO::getModifyTime);
        return dataSetMapper.selectList(wrapper);
    }

    public void dataSetParamBatch(List<DataSetParamVO> dataSetParamDtoList, String setCode) {
        dataSetParamService.delete(
                new QueryWrapper<DataSetParamDO>()
                        .lambda()
                        .eq(DataSetParamDO::getSetCode, setCode)
        );
        if (null == dataSetParamDtoList || dataSetParamDtoList.size() <= 0) {
            return;
        }
//        List<DataSetParamDO> dataSetParamList = new ArrayList<>();
        dataSetParamDtoList.forEach(dataSetParamDto -> {
            DataSetParamDO dataSetParamDO = new DataSetParamDO();
            BeanUtils.copyProperties(dataSetParamDto, dataSetParamDO);
            dataSetParamDO.setSetCode(setCode);
            //不采用批量
            dataSetParamService.insert(dataSetParamDO);
//            dataSetParamList.add(dataSetParamDO);
        });
//        dataSetParamService.insertBatch(dataSetParamList);

    }

    public void dataSetTransformBatch(List<DataSetTransformVO> dataSetTransformDtoList, String setCode) {
        dataSetTransformService.delete(
                new QueryWrapper<DataSetTransformDO>()
                        .lambda()
                        .eq(DataSetTransformDO::getSetCode, setCode)
        );
        if (null == dataSetTransformDtoList || dataSetTransformDtoList.size() <= 0) {
            return;
        }
//        List<DataSetTransformDO> dataSetTransformList = new ArrayList<>();
        for (int i = 0; i < dataSetTransformDtoList.size(); i++) {
            DataSetTransformDO dataSetTransformDO = new DataSetTransformDO();
            BeanUtils.copyProperties(dataSetTransformDtoList.get(i), dataSetTransformDO);
            dataSetTransformDO.setOrderNum(i + 1);
            dataSetTransformDO.setSetCode(setCode);
            //不采用批量
            dataSetTransformService.insert(dataSetTransformDO);
//            dataSetTransformList.add(dataSetTransformDO);
        }
//        dataSetTransformService.insertBatch(dataSetTransformList);
    }

    /**
     * dataSetParamDtoList转map
     *
     * @param dataSetParamDtoList
     * @return
     */
    public Map<String, Object> setContextData(List<DataSetParamVO> dataSetParamDtoList) {
        Map<String, Object> map = new HashMap<>();
        if (null != dataSetParamDtoList && dataSetParamDtoList.size() > 0) {
            dataSetParamDtoList.forEach(dataSetParamDto -> map.put(dataSetParamDto.getParamName(), dataSetParamDto.getSampleItem()));
        }
        return map;
    }

}
